<?php
/**
 * HTML generating class
 *
 * Use this class to transform array's and objects to HTML (and CSS, and Javascript)
 *
 * PHP version 5
 *
 * Copyright (C) 2012 Ewald van Gemert (ewald@vangee.nl)
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 
 * associated documentation files (the "Software"), to deal in the Software without restriction,
 * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial
 * portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 
 * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 
 * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 * @category   Development tool
 * @package    MySQLcompare
 * @author     Ewald van Gemert <ewald@vangee.nl>
 * @license    MIT 3
 * @version    SVN: 
 * @link       http://code.google.com/p/mysqlcompare
 * @since      File available since Release 0.9
 */

// ###########################################################################
// Class creating HTML results
// ###########################################################################
class HTMLRESULT {
	private $pagesize = 100;
	
	private function shortentext($val, $steps) {
		if ($steps==1) {
			if (strlen($val)>12) $val = substr($val, 0, 10)."...";
		} else {
			if (strlen($val)>200) {
				$val = "<span class=\"smalltxt\">".substr($val, 0, 200)."...</span>";
			} else {
				if (strlen($val)>20) $val = "<span class=\"smalltxt\">".substr($val, 0, 60)."...</span>";
			}
		}
		return $val;
	}
	
	// ***********************************************************************
	// public functions
	// ***********************************************************************
	public function __construct() {
		return true;
	}
	
	function definitionlbl($inp) {
		return ($inp) ? '<span class="badge badge-success">identical</span>' : '<span class="badge badge-error">different</span>';
	}
	
	function definition($table,$metaA,$rowsA,$diffA,$metaB,$rowsB,$diffB) {
		return '<div class="row">
				  <div class="span6">
					<div class="well">
					  <h3>'.$table.'</h3>
					  Columns # '.$metaA.'<br/>
					  Records # '.$rowsA.'
					</div>
					<pre>'.$diffA.'</pre>
				  </div>
				  <div class="span6">
					<div class="well">
					  <h3>'.$table.'</h3>
					  Columns # '.$metaB.'<br/>
					  Records # '.$rowsB.'
					</div>
					<pre>'.$diffB.'</pre>
				  </div>
			</div>';
	}

	function keyCheckbox($interSect, $table, $selkeys, $allkeys, $primKeys, $keyvalid) {
		$result = '<form id="frmKeys" method="POST" class="bs-docs-example">Choose your key(s)
					<a href="#" rel="tooltip" data-original-title="Another one here too"><i class="icon-exclamation-sign"></i></a> here:
					<a class="btn btn-mini" href="javascript:btnAlternativeKeys('."'{$table}'".');"><i class="icon-refresh"></i></a>
					<label class="checkbox inline">';
		foreach($allkeys as $key) {
			$checked = (in_array($key, $selkeys)) ? " checked" : "";
			$name    = (in_array($key, $primKeys)) ? "<u>$key</u>" : "$key";
			$result .= '<label class="checkbox inline"><input type="checkbox" value="'.$key.'"'.$checked.'>'.$name.'</label>';
		}
		if ($keyvalid==false) $result .= '<span style="color: red; font-weight: bold">The key you are using is not joining records unique.</span>';
		$result .= '</form>';
		return $result;
	}
	
	function trhead($cols, $maxcols=24) {
		$result = "";
		foreach ($cols as $col) {$maxcols--; if ($maxcols>0) $result .= "<th>{$col}</th>";}
		return $result;
	}
	
	function rowsDiff($objs, $keys, $allcols, $page=1, $pagesize=null, $maxcols=24) {
		$pagesize = (isset($pagesize)) ? $pagesize : $this->pagesize;
		$tbldiff = "";
		$r = 0;
		// Skip pev pages, if page > 1
		for ($i = 1; $i <= (($page-1)*$this->pagesize); $i++) next($objs);
		foreach ($objs as $obj) {
			$trbackground = (($r % 2)==0) ? " backgrey" : " white";
			$rowa = $obj['rowa'];
			$rowb = $obj['rowb'];
			$key = $obj['keys'];
			$jsonkey = str_replace(array("'", '"'), array("FIX-JSON-SINGLE-QUOTE", "'"), json_encode($obj['sel']));
			
			// Teken de A row
			$tbldiff .= "<tr class=\"topline{$trbackground}\">
				<td width=\"22\"><b>A</b></td>
				<td width=\"22\" rowspan=\"2\" style=\"vertical-align: middle\"><button class=\"btn btn-mini btnprimary btnrowcompare\" relid=\"{$jsonkey}\" href=\"#\"><i class=\"icon-search\"></i></button></td>";
			foreach ($key as $k) { // Hier de key velden vooraan neerzetten.
				$tbldiff .= "<td>{$k}</td>";
			}
			$i = 0;
			foreach ($allcols as $fld) {
				// Dan overige velden (behalve key velden)
				$i++;
				if (isset($rowa[$fld])) {
					$val = $rowa[$fld];
					$val = htmlentities($val);
					if (isset($rowb[$fld])&&($rowa[$fld]==$rowb[$fld])) {
						$val = $this->shortentext($val, 1);
						$class = "";
					} else {
						$val = $this->shortentext($val, 2);
						$class = "diff";
					}
					if (!in_array($fld, $keys)&&($i<$maxcols)) $tbldiff .= "<td class=\"{$class}\">{$val}</td>";
				} else {
					$tbldiff .= "<td><b>EMPTY</b></td>";
				}
			}
		
			$tbldiff .= "</tr>\n";
			$tbldiff .= "<tr class=\"{$trbackground}\"><td width=\"22\"><b>B</b></td>";
			foreach ($key as $k) { // Hier de key velden vooraan neerzetten.
				$tbldiff .= "<td>{$k}</td>";
			}		
			$i = 0;
			foreach ($allcols as $fld) {
				$i++;
				if (isset($rowb[$fld])) {
					$val = $rowb[$fld];
					$val = htmlentities($val);
					if (isset($rowa[$fld])&&($rowa[$fld]==$rowb[$fld])) {
						$val = $this->shortentext($val, 1);
						$class = "";
					} else {
						$val = $this->shortentext($val, 2);
						$class = "diff";
					}
					if (!in_array($fld, $keys)&&($i<$maxcols)) $tbldiff .= "<td class=\"{$class}\">{$val}</td>";
				} else {
					$tbldiff .= "<td><b>EMPTY</b></td>";
				}
			}		
			$tbldiff .= "</tr>\n";
			$r++;
			if ($pagesize==$r) break;
		}
		return $tbldiff;
	}
	
	function tblToHTML($objs, $keys, $allcols, $page=2, $pagesize=null, $maxcols=24) {
		$pagesize = (isset($pagesize)) ? $pagesize : $this->pagesize;
		$tblHTML  = '';
		$r = 0;
		foreach ($objs as $obj) {
			$row = $obj['row'];
			$key = $obj['keys'];
			$tblHTML .= "<tr>";
			foreach ($key as $k) { // Hier de key velden vooraan neerzetten.
				$tblHTML .= "<td>{$k}</td>";
			}
			$i = 0;
			foreach ($row as $fld => $val) { // Dan overige velden (behalve key velden)
				$val = htmlentities($val);
				$val = $this->shortentext($val, 2);
				$i++;
				if (!in_array($fld, $keys)&&($i<$maxcols)) $tblHTML .= "<td>{$val}</td>";
			}
			$tblHTML .= "</tr>\n";
			$r++;
			if ($pagesize==$r) break;
		}
		return $tblHTML;
	}
	
	function deepResult($choosekey, $definitionlbl, $rowsDiff, $rowsRecA, $rowsRecB, $rowsIdent, $definition, $trhead, $tbldiff, $tblreca, $tblrecb, $tblident) {
		return array("lblchoosekey"  => $choosekey
				,	 "lbldefinition" => 'Tabledefinition '.$definitionlbl
				,	 "lbldifferent"  => 'Different Records <span class="badge badge-important">'.$rowsDiff.'</span>'
				,	 "lblrecordsa"   => 'Records in A <span class="badge badge-warning">'.$rowsRecA.'</span>'
				,	 "lblrecordsb"   => 'Records in B <span class="badge badge-warning">'.$rowsRecB.'</span>'
				,	 "lblidentical"  => 'Identical records <span class="badge badge-success">'.$rowsIdent.'</span>'
				,	 "definition"  => $definition
				,	 "different"  => '<table id="resTable" class="deepcompare table table-bordered">
									<thead><tr><th>[db]</th><th>&nbsp</th>'.$trhead.'</tr></thead>
									<tbody>'.$tbldiff.'</tbody>
								</table>'
				,	 "recordsa"  => '<table id="resTable" class="deepcompare table table-bordered table-striped">
									<thead><tr>'.$trhead.'</tr></thead>
									<tbody>'.$tblreca.'</tbody>
								</table>'
				,	 "recordsb"  => '<table id="resTable" class="deepcompare table table-bordered table-striped">
									<thead><tr>'.$trhead.'</tr></thead>
									<tbody>'.$tblrecb.'</tbody>
								</table>'
				,	 "identical"  => '<table id="resTable" class="deepcompare table table-bordered table-striped">
									<thead><tr>'.$trhead.'</tr></thead>
									<tbody>'.$tblident.'</tbody>
								</table>');
	}
	
	function rowResult($rows) {
		// Use placeholder `null`, when fields are `null`
		$tblrows = '';
		foreach ($rows as $row) {
			$info = "";
			switch ($row['type']) {
				case "text":
					$lines = (substr_count("{$row['fieldA']}{$row['fieldB']}", "\n") / 2);
					if ($lines > 20) $lines = 20;
					$flda = "<div class=\"span7\"><textarea id=\"a_{$row['colnam']}\" name=\"a_{$row['colnam']}\" class=\"codemirror\" rows=\"{$lines}\">{$row['fieldA']}</textarea></div>";
					$fldb = "<div class=\"span7\"><textarea id=\"b_{$row['colnam']}\" name=\"b_{$row['colnam']}\" class=\"span5 codemirror\" rows=\"{$lines}\">{$row['fieldB']}</textarea></div>";
					$info = "<br/><div style=\"text-align: left\">A: {$row['charsetA']}<br>{$row['charsA']} chars<br>{$row['sizeA']} bytes</div>".
							"<br/>".
							"<div style=\"text-align: right\">B:{$row['charsetB']}<br>{$row['charsB']} chars<br>{$row['sizeB']} bytes<div>";
					break;
				case "input":
					$flda = "<input name=\"a_{$row['colnam']}\" class=\"span5\" type=\"text\" value=\"{$row['fieldA']}\">";
					$fldb = "<input name=\"b_{$row['colnam']}\" class=\"span5\" type=\"text\" value=\"{$row['fieldA']}\">";
					break;
			}
			$class = ("{$row['fieldA']}"!="{$row['fieldB']}") ? " class=\"diff\"" : "";
			$tblrows .= "<tr><td>{$flda}</td><td{$class}><div style=\"text-align: center\">{$row['colnam']}</div>{$info}</td><td>{$fldb}</td></tr>";
		}
		return '<div>
					<div>
					 '."<a href=\"javascript:$('#myCarousel').carousel(0);\"><i class=\"icon-backward\"></i> show DB</a>
					    <a href=\"javascript:$('#myCarousel').carousel(1);\"><i class=\"icon-chevron-left\"></i> show Table</a>".'
					</div>
					<table id="resTable" class="rowcompare table table-bordered table-striped">
						<tbody>'.$tblrows.'</tbody>
					</table>
					<div class="form-actions">
					  <button type="submit" class="btn btn-primary">Save changes</button>
					  <button type="button" class="btn" onclick="'."$('#myCarousel').carousel(1);".'">Cancel</button>
					</div>
				</div>
				<script>
					// Codemirror
					function isFullScreen(cm) {
					  return /\bCodeMirror-fullscreen\b/.test(cm.getWrapperElement().className);
					}
					function winHeight() {
					  return window.innerHeight || (document.documentElement || document.body).clientHeight;
					}
					function setFullScreen(cm, full) {
					  var wrap = cm.getWrapperElement();
					  if (full) {
						wrap.className += " CodeMirror-fullscreen";
						wrap.style.height = winHeight() + "px";
						document.documentElement.style.overflow = "hidden";
					  } else {
						wrap.className = wrap.className.replace(" CodeMirror-fullscreen", "");
						wrap.style.height = "";
						document.documentElement.style.overflow = "";
					  }
					  cm.refresh();
					}
					CodeMirror.on(window, "resize", function() {
					  var showing = document.body.getElementsByClassName("CodeMirror-fullscreen")[0];
					  if (!showing) return;
					  showing.CodeMirror.getWrapperElement().style.height = winHeight() + "px";
					});

	
					$(".codemirror").each(function(event) {
						var editor = CodeMirror.fromTextArea(document.getElementById($(this).attr("id")), {
						  lineNumbers: true,
						  extraKeys: {
							"F11": function(cm) {
							  setFullScreen(cm, !isFullScreen(cm));
							},
							"Esc": function(cm) {
							  if (isFullScreen(cm)) setFullScreen(cm, false);
							}
						  }
						});
					});					
				</script>';
	}


	function compareTablesInTrRow($data) {
		$name = $data['tablename'];
		$equal = $data['result']['equal'];
		$index = $data['curindex'];
		$classSame = ($equal==1) ? "same" : "";
		$classSystem = (in_array($name, array("modx_manager_log","modx_event_log"))) ? "system" : "";
		$trClass = trim(str_replace("  ", " ", "{$classSame} {$classSystem}"));
		$classA = $data['result']['a']['class'];
		$classB = $data['result']['b']['class'];
		$tbla = '<span class="badge badge-'.$classA.'">'.$data['result']['a']['rows'].'</span>';
		$tblb = '<span class="badge badge-'.$classB.'">'.$data['result']['b']['rows'].'</span>';
	
	$sync = '<a class="btn btn-mini syncb2a" relid="'.$index.'" tbl="'.$name.'" href="#"><i class="icon-arrow-left icon-black"></i>sync</a>&nbsp;' .
			'<select id="selact'.$index.'" class="span2" style="padding: 0px; margin: 0px; height: 20px; line-height: 20px; font-size: 10px;">' .
				'<option value="">none</option><!--<option value="newrows">New rows</option>--><option value="allrows">All rows</option><option value="definition">Definition</option><option value="all">All</option><option value="del">Delete table</option>' .
			'</select>&nbsp;' .
			'<a class="btn btn-mini synca2b" relid="'.$index.'" tbl="'.$name.'" href="#">sync<i class="icon-arrow-right icon-black"></i></a>';					
	$result = $data['result']['reason'];
	$button = (($data['result']['a']['rows']>0)&&($data['result']['b']['rows']>0)) ? 
			'<button class="btn btn-mini btn-primary deepcompare" onclick="deepCompareDB('."'".$name."'".');">Deep compare</button>' : '&nbsp;';

	return '<tr id="tr'.$name.'" class="'.$trClass.'"><td class="right">'.$index.'</td><td>'.$name.'</td><td>'.$tbla.'</td><td class="center">'.$sync.'</td><td>'.$tblb.'</td><td>'.$result.'</td><td>'.$button.'</td></tr>';
	
	}
}
